Skip to content

Conversation

@AndrewTKent
Copy link
Contributor

@AndrewTKent AndrewTKent commented Jan 27, 2026

Fixes #149794

Summary

The previous implementation converted the entire Duration to f64 before multiplying/dividing, which caused precision loss because Duration has ~93 bits of precision (u64 secs + u32 nanos) but f64 only has 53 bits of mantissa.

This caused issues like:

  • Duration::MAX.mul_f32(1.0) panicking due to overflow
  • d.mul_f64(1.0) not preserving the exact value

Solution

Multiply/divide seconds and nanoseconds separately, then combine the results. This preserves precision for the common case while properly handling edge cases.

Changes

  • Add helper function duration_from_float_secs() to reduce code duplication
  • Add #[track_caller] to all four methods for better panic messages
  • Add explicit infinity check with is_infinite()
  • Check overflow before casting to u64 and use checked_add()
  • Clamp final nanoseconds with .max(0.0) to handle floating-point rounding errors
  • Update doctest expected values to match new (correct) behavior
  • Add comprehensive tests for edge cases (overflow, infinity, subnormals, zero, boundaries)

Test plan

  • All existing time tests pass (70 tests)
  • All doctests pass
  • New tests cover: overflow, infinity, negative infinity, subnormals, zero duration, rounding boundaries, small durations, large factors

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-libs Relevant to the library team, which will review and decide on the PR/issue. labels Jan 27, 2026
@rustbot
Copy link
Collaborator

rustbot commented Jan 27, 2026

r? @tgross35

rustbot has assigned @tgross35.
They will have a look at your PR within the next two weeks and either review your PR or reassign to another reviewer.

Use r? to explicitly pick a reviewer

@rustbot

This comment has been minimized.

@AndrewTKent AndrewTKent force-pushed the fix-duration-float-precision branch from 5b8b932 to fe77711 Compare January 27, 2026 23:35
The previous implementation converted the entire Duration to f64 before
multiplying/dividing, which caused precision loss because Duration has
~93 bits of precision (u64 secs + u32 nanos) but f64 only has 53 bits
of mantissa.

This caused issues like:
- `Duration::MAX.mul_f32(1.0)` panicking due to overflow
- `d.mul_f64(1.0)` not preserving the exact value

The fix multiplies/divides seconds and nanoseconds separately, then
combines the results. This preserves precision for the common case
while properly handling edge cases (NaN, infinity, overflow).

Changes:
- Add helper function `duration_from_float_secs()` to reduce duplication
- Add `#[track_caller]` to all four methods for better panic messages
- Add explicit infinity check with `is_infinite()`
- Check overflow before casting to u64 and use `checked_add()`
- Clamp final nanoseconds with `.max(0.0)` for floating-point errors
- Update doctest expected values to match new (correct) behavior
- Add comprehensive tests for edge cases
@AndrewTKent AndrewTKent force-pushed the fix-duration-float-precision branch from fe77711 to 03b8738 Compare January 27, 2026 23:48
@tgross35
Copy link
Contributor

Cc @quaternic as the issue author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-libs Relevant to the library team, which will review and decide on the PR/issue.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Loss of precision in Duration::mul_f32 (and mul_f64)

3 participants